package com.wstuo.common.jbpm.service;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.security.dao.IOrganizationDAO;
import com.wstuo.common.security.dao.IUserDAO;
import com.wstuo.common.security.entity.Organization;
import com.wstuo.common.security.entity.User;
import com.wstuo.common.security.utils.FileEncodeUtils;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.bpm.dao.IFlowActivityDAO;
import com.wstuo.common.bpm.dao.IFlowPropertyDAO;
import com.wstuo.common.bpm.dao.IFlowTransitionDAO;
import com.wstuo.common.bpm.dto.FlowActivityDTO;
import com.wstuo.common.bpm.dto.FlowPropertyDTO;
import com.wstuo.common.bpm.dto.FlowTransitionDTO;
import com.wstuo.common.bpm.entity.FlowActivity;
import com.wstuo.common.bpm.entity.FlowProperty;
import com.wstuo.common.bpm.entity.FlowTransition;
import com.wstuo.common.bpm.service.IFlowPropertyService;
import com.wstuo.common.jbpm.FlowDesigner;
import com.wstuo.common.jbpm.IJbpmFacade;
import com.wstuo.common.jbpm.dao.IJbpmTaskDAO;
import com.wstuo.common.jbpm.entity.JbpmTask;

import org.apache.struts2.json.JSONException;
import org.apache.struts2.json.JSONUtil;

/**
 * Flow Property Service Class
 * @author wstuo
 *
 */
public class FlowPropertyService implements IFlowPropertyService {
	
	@Autowired
	private IFlowPropertyDAO flowPropertyDAO;
	@Autowired
	private IFlowActivityDAO flowActivityDAO;
	@Autowired
	private IFlowTransitionDAO flowTransitionDAO;
	@Autowired
	private IJbpmFacade jbpmFacade;
	@Autowired
	private IUserDAO userDAO;
	@Autowired
	private IOrganizationDAO organizationDAO;
	@Autowired
	private IJbpmTaskDAO jbpmTaskDAO;
	
	/**
	 * Save Flow Property
	 * @param flowPropertyDTO
	 */
	@Transactional
	public void saveFlowProperty(FlowPropertyDTO flowPropertyDTO){
		FlowProperty entity = new FlowProperty();
		FlowPropertyDTO.dto2entity(flowPropertyDTO, entity);
		flowPropertyDAO.save(entity);
		//活动
		List<FlowActivity> flowActivitys = new ArrayList<FlowActivity>();
		FlowDesigner fd  = new FlowDesigner();
		String deployUrl =FlowDesigner.PROCESS_FILE_PATH+"/"+flowPropertyDTO.getProcessDefinitionId()+".jpdl.xml";
		Map<String,Map<String,String>> map=fd.findNodeMapByNodeName(new File(deployUrl), "task");
/*		try {
			System.err.println(JSONUtil.serialize(map)+"============1=");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
*/		if(flowPropertyDTO.getFlowActivityDTO()!=null){
			Map<Integer,Map<String,String>> attrs=new HashMap<Integer,Map<String,String>>();
			for(FlowActivityDTO flowActivityDTO : flowPropertyDTO.getFlowActivityDTO()){//活动
				//System.err.println(flowActivityDTO.getActivityName()+"=============");
				
				FlowActivity flowActivity = new FlowActivity();
				FlowActivityDTO.dto2entity(flowActivityDTO, flowActivity);
				flowActivity.setFlowProperty(entity);
				//过渡start
				List<FlowTransition> flowTransitions = new ArrayList<FlowTransition>();
				if(flowActivityDTO.getFlowTransitionDto()!=null){
					for(FlowTransitionDTO flowTransitionDTO : flowActivityDTO.getFlowTransitionDto()){
						FlowTransition flowTransition = new FlowTransition();
						FlowTransitionDTO.dto2entity(flowTransitionDTO, flowTransition);
						flowTransitionDAO.save(flowTransition);
						flowTransitions.add(flowTransition);
					}
				}
				flowActivity.setFlowTransition(flowTransitions);
				//过渡end
				Map<String,String> act=map.get(flowActivityDTO.getActivityName());
				if(act!=null){
					flowActivity.setStatusNo(Long.parseLong(act.get("status")));
					flowActivity.setCandidateGroupsName(act.get("candidate-groups"));
					flowActivity.setCandidateGroupsNo(act.get("candidate-groupsNo"));
					flowActivity.setCandidateUsersName(act.get("candidate-users"));
					flowActivity.setCandidateUsersNo(act.get("candidate-usersNo"));
					if(act.get("noticeRuleId")!=null)
						flowActivity.setNoticeRuleIds(act.get("noticeRuleId"));
					if(act.get("matchRuleId")!=null){
						flowActivity.setMatchRuleIds(act.get("matchRuleId"));
						flowActivity.setAssignType("ruleAssignee");
					}
				}
				flowActivity.setIsUpdateEventAssign(true);
				flowActivity.setAllowUdateDefaultAssignee(true);
				flowActivity.setAllowUdateDefaultAssigneeGroup(true);
				
				flowActivityDAO.save(flowActivity);
				if(act!=null){
					Map<String,String> attr=new HashMap<String,String>();
					attr.put("id", flowActivity.getId()+"");
					attr.put("index", act.get("index"));
					attrs.put(Integer.parseInt(act.get("index")), attr);
				}
				flowActivitys.add(flowActivity);
			}
			new FlowDesigner().updateNode(deployUrl, attrs, "task");
			entity.setFlowActivity(flowActivitys);
		}
	}
	
	/**
	 * Delete Flow Property
	 * @param deploymentId
	 */
	@Transactional
	public void deleteFlowProperty(String deploymentId) {
		List<FlowProperty> fps = flowPropertyDAO.findBy("deploymentId", deploymentId);
		flowPropertyDAO.deleteAll(fps);
	}



	/**
	 * Find Flow Property Details By DeploymentID
	 * @param processDefinitionId
	 * @return FlowPropertyDTO
	 */
	@Transactional
	public FlowPropertyDTO findFlowPropertyByProcessDefinitionId(String processDefinitionId){
		FlowPropertyDTO flowPropertyDTO = new FlowPropertyDTO();
		FlowProperty entity = flowPropertyDAO.findUniqueBy("processDefinitionId", processDefinitionId);
		if(entity==null){//如果还没有保存到数据，则根据流程ID去获取，并返回FlowPropertyDTO，再保存到数据库中
			flowPropertyDTO = jbpmFacade.findProcessDefinitionActivity(processDefinitionId);
			if(flowPropertyDTO.getDeploymentId()!=null && flowPropertyDTO.getProcessDefinitionId()!=null){
				saveFlowProperty(flowPropertyDTO);
			}
			entity = flowPropertyDAO.findUniqueBy("processDefinitionId", processDefinitionId);
			entity2dto(entity,flowPropertyDTO);
			
		}else{
			entity2dto(entity,flowPropertyDTO);
		}
		return flowPropertyDTO;
	}
	@Transactional
	public String findFlowPropertyByDeploymentId(String deploymentId){
		FlowPropertyDTO flowPropertyDTO = new FlowPropertyDTO();
		FlowProperty entity = flowPropertyDAO.findUniqueBy("deploymentId", deploymentId);
		if(entity==null){//如果还没有保存到数据，则根据流程ID去获取，并返回FlowPropertyDTO，再保存到数据库中
			flowPropertyDTO = jbpmFacade.findProcessDefinitionActivity(deploymentId);
			if(flowPropertyDTO.getDeploymentId()!=null && flowPropertyDTO.getProcessDefinitionId()!=null){
				String deployUrl =FlowDesigner.PROCESS_FILE_PATH+"/result.jpdl.xml";
				String toUrl= FlowDesigner.PROCESS_FILE_PATH+"/"+flowPropertyDTO.getProcessDefinitionId()+".jpdl.xml";
				FileEncodeUtils.copyFile(deployUrl, toUrl, true);//copy文件
				
				saveFlowProperty(flowPropertyDTO);
			}
			return flowPropertyDTO.getProcessDefinitionId();
		}
		return "";
	}
	/**
	 * Entity to DTO Class
	 * @param entity
	 * @param dto
	 */
	@Transactional
	private void entity2dto(FlowProperty entity,FlowPropertyDTO dto){
		FlowPropertyDTO.entity2dto(entity, dto);
		List<FlowActivity> flowActivitys = entity.getFlowActivity();
		if(flowActivitys!=null){
			List<FlowActivityDTO> flowActivityDtos = new ArrayList<FlowActivityDTO>();
			for(FlowActivity flowActivity : flowActivitys){
				FlowActivityDTO flowActivityDTO = new FlowActivityDTO();
				FlowActivityDTO.entity2dto(flowActivity, flowActivityDTO);
				
				//FlowTransition start
				List<FlowTransitionDTO> flowTransitionDtos = new ArrayList<FlowTransitionDTO>();
				List<FlowTransition> flowTransitions = flowActivity.getFlowTransition();
				if(flowTransitions!=null){
					for(FlowTransition flowTransition : flowTransitions){
						FlowTransitionDTO flowTransitionDTO = new FlowTransitionDTO();
						FlowTransitionDTO.entity2dto(flowTransition, flowTransitionDTO);
						flowTransitionDtos.add(flowTransitionDTO);
					}
					
				}
				flowActivityDTO.setFlowTransitionDto(flowTransitionDtos);
				//FlowTransition end
				
				flowActivityDtos.add(flowActivityDTO);
			}
			
			dto.setFlowActivityDTO(flowActivityDtos);
		}
	}
	/**
	 * Update Flow Activity
	 * @param dto
	 */
	@Transactional
	public void updateFlowActivity(FlowActivityDTO dto){
		FlowActivity fa = flowActivityDAO.findById(dto.getId());
		dto.setActivityType(fa.getActivityType());
		dto.setActivityName(fa.getActivityName());
		FlowActivityDTO.dto2entity(dto, fa);
		fa.setVariablesAssigneeType(dto.getVariablesAssigneeType());
		if(dto.getAssigneeNo()!=null){
			fa.setAssignee(dto.getAssigneeNo());
		}else{
			fa.setAssignee(null);
		}
		if(dto.getGroupNo()!=null){
			fa.setGroups(dto.getGroupNo());
		}else{
			fa.setGroups(null);
		}
		
		if(dto.getTaskActions()!=null){
			StringBuffer s = new StringBuffer();
			for(String str : dto.getTaskActions()){
				if("".equals(s.toString()))
					s.append(str);
				else
					s.append(","+str);
			}
			fa.setTaskAction(s.toString());
		}else{
			fa.setTaskAction(null);
		}
		
		if(dto.getRoleCodes()!=null){
			StringBuffer s = new StringBuffer();
			for(String str : dto.getRoleCodes()){
				if("".equals(s.toString()))
					s.append(str);
				else
					s.append(","+str);
			}
			fa.setRoleCode(s.toString());
		}else{
			fa.setRoleCode(null);
		}
		if(StringUtils.hasText(fa.getMatchRuleIds())){
			fa.setAssignType("ruleAssignee");
		}
		fa.setIsUpdateEventAssign(true);
		fa.setAllowUdateDefaultAssignee(true);
		fa.setAllowUdateDefaultAssigneeGroup(true);
		Map<Integer,Map<String,String>> attrs=new HashMap<Integer,Map<String,String>>();
		Map<String,String> attr=new HashMap<String,String>();
		attr.put("id", fa.getId()+"");
		attr.put("index", dto.getIndex()+"");
		attr.put("candidate-groups",fa.getCandidateGroupsName());
		attr.put("candidate-groupsNo",fa.getCandidateGroupsNo());
		attr.put("candidate-users",fa.getCandidateUsersName());
		attr.put("candidate-usersNo",fa.getCandidateUsersNo());
		
		attr.put("noticeRule",fa.getNoticeRule());
		attr.put("noticeRuleId",fa.getNoticeRuleIds());
		attr.put("matchRuleId",fa.getMatchRuleIds());
		attrs.put(dto.getIndex(), attr);
		String deployUrl =FlowDesigner.PROCESS_FILE_PATH+"/"+fa.getFlowProperty().getProcessDefinitionId()+".jpdl.xml";
		new FlowDesigner().updateNode(deployUrl, attrs, "task");
		flowActivityDAO.merge(fa);
	}
	/**
	 * Find Flow Activity By Id
	 * @param flowActivityId
	 * @return process activity id
	 */
	@Transactional
	public FlowActivityDTO findFlowActivityById(Long flowActivityId){
		FlowActivityDTO dto = new FlowActivityDTO();
		FlowActivity fa = flowActivityDAO.findById(flowActivityId);
		FlowActivityDTO.entity2dto(fa, dto);
		dto.setNoticeRuleId(fa.getNoticeRuleId());
		dto.setMatchRuleId(fa.getMatchRuleId());
		if(fa.getAssignee()!=null){
			User assignee = userDAO.findById(fa.getAssignee());
			if(assignee!=null){
				dto.setAssigneeName(assignee.getFullName());
				dto.setAssigneeNo(assignee.getUserId());
			}
		}
		
		if(fa.getGroups()!=null){
			Organization group = organizationDAO.findById(fa.getGroups());
			if(group!=null){
				dto.setGroupName(group.getOrgName());
				dto.setGroupNo(group.getOrgNo());
			}
			
		}
		if(fa.getTaskAction()!=null){
			String[] taskActions = fa.getTaskAction().split(",");
			Set<String> tas = new HashSet<String>();
			for(String str:taskActions){
				tas.add(str);
			}
			dto.setTaskActions(tas);
		}
		if(fa.getRoleCode()!=null){
			String[] roleCodes = fa.getRoleCode().split(",");
			Set<String> tas = new HashSet<String>();
			for(String str:roleCodes){
				tas.add(str);
			}
			dto.setRoleCodes(tas);
		}
		return dto;
	}
	/**
	 * 查询流程动作
	 * @param processDefinitionId 流程定义ID
	 * @param activityType 活动类型
	 * @param activityName 活动名称
	 * @return FlowActivityDTO
	 */
	@Transactional
	public FlowActivityDTO findFlowActivity(String processDefinitionId,String[] activityType, String activityName) {
		FlowActivityDTO dto = new FlowActivityDTO();
		
		FlowActivity fa = flowActivityDAO.findFlowActivityByDeploymentId(processDefinitionId, activityType, activityName);
		if(fa!=null){
			FlowActivityDTO.entity2dto(fa, dto);
			dto.setNoticeRuleId(fa.getNoticeRuleId());
			dto.setMatchRuleId(fa.getMatchRuleId());
			if(fa.getAssignee()!=null){
				User assignee = userDAO.findById(fa.getAssignee());
				if(assignee!=null){
					dto.setAssigneeName(assignee.getFullName());
					dto.setAssigneeNo(assignee.getUserId());
				}
			}
			
			if(fa.getGroups()!=null){
				Organization group = organizationDAO.findById(fa.getGroups());
				if(group!=null){
					dto.setGroupName(group.getOrgName());
					dto.setGroupNo(group.getOrgNo());
				}
				
			}
			
			if(fa.getTaskAction()!=null){
				String[] taskActions = fa.getTaskAction().split(",");
				Set<String> tas = new HashSet<String>();
				for(String str:taskActions){
					tas.add(str);
				}
				dto.setTaskActions(tas);
			}
		}
		return dto;
	}
	/**
	 * 是否存在该任务
	 * @param taskId String type
	 * @return boolean
	 */
	public boolean isExistTaskId(String taskId){
		boolean result = false;
		JbpmTask task = jbpmTaskDAO.findById(Long.parseLong(taskId));
		if(task!=null){
			result = true;
		}
		return result;
	}
}
